/**
 * <p><b>Title:</b> SysDictDataController.java </p>
 * @Package com.wondertek.oes.bc.setting.controller
 */
package com.wondertek.poms.setting.controller;


import com.wondertek.poms.common.constant.Constants;
import com.wondertek.poms.common.controller.BaseController;
import com.wondertek.poms.common.exception.BusinessException;
import com.wondertek.poms.common.exception.MessageCodes;
import com.wondertek.poms.common.log.MethodLog;
import com.wondertek.poms.common.utils.validate.ValidateFilter;
import com.wondertek.poms.common.vo.ResultBean;
import com.wondertek.poms.core.service.ISysDictDataService;
import com.wondertek.poms.core.service.ISysDictTypeService;
import com.wondertek.poms.dao.po.SysDictData;
import com.wondertek.poms.dao.po.SysDictType;
import com.wondertek.poms.setting.vo.SysDictDataVo;
import com.wondertek.poms.setting.vo.TypesAndFlagVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * <p><b>SysDictDataController Description:</b> 字典数据表Controller层实现</p>
 * @author wzq
 * <p><b>DATE</b> 2019-08-13 11:02:01</p>
 */
@Api("字典数据")
@RestController
@Scope("prototype")
@RequestMapping(value="/dict-data")
public class SysDictDataController extends BaseController {

	@Autowired
	private StringRedisTemplate redisTemplate;
	@Autowired
	private ISysDictDataService sysDictDataService;
	@Autowired
	private ISysDictTypeService sysDictTypeService;

	/***
	 * @Author wzq
	 * @Description //此结果返回字典数据树形结构
	 * @Date 17:01 2019/9/7
	 * @Param [sysDictDataVo]
	 * @return com.wondertek.oes.commons.utils.ResultBean
	 **/
	@ApiOperation("字典数据列表")
	@GetMapping("/list")
	@ResponseBody
	@MethodLog(module = "字典数据列表")
	public ResultBean list(SysDictDataVo sysDictDataVo,
						   @RequestParam(defaultValue = "1") int page,
						   @RequestParam(defaultValue = "99999999") int rows,
						   @RequestParam(defaultValue = "sort") String sidx,
						   @RequestParam(defaultValue = "asc") String sord) {
		if (StringUtils.isBlank(sysDictDataVo.getType())) {
			throw new BusinessException(MessageCodes.M980717);
		}

		SysDictData sysDictData = new SysDictData();
		BeanUtils.copyProperties(sysDictDataVo, sysDictData);
		//首先查出满足查询条件的所有字典数据
		Page<SysDictData> pageDataList = sysDictDataService
				.findAllData(sysDictData, page, rows, sord, sidx);
		List<SysDictData> allDataList = pageDataList.getContent();
		/**
		 * 解决查询结果中不满足树形递归条件而查询不出的问题：
		 * 因为咱们的setDictTree方法是默认从根节点查询的，假如现在用户输入的条件子节点满足，而父节点不满足，则会查不到这个子节点的数据。
		 * 所以我把所有数据都存到map中，如果在组成树的过程中有些节点没有取到,则会把map中这些没有取到的数据添加到返回的list中
		 */
		Map<Long, SysDictData> allMap = new HashMap<>(allDataList.size());
		allDataList.forEach(temp -> {
			allMap.put(temp.getId(), temp);
		});

		List<SysDictData> list = new ArrayList<>();
		setDictTree(0L, allDataList, list, allMap);
		allMap.forEach((k, v) -> {
			list.add(substrParentIds(v));
		});
		return ResultBean.ok(list);
	}

	@ApiOperation("字典数据新增")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "parentId", required = true),
			@ApiImplicitParam(name = "parentIds", required = true),
			@ApiImplicitParam(name = "sort", required = true),
			@ApiImplicitParam(name = "isleaf", required = true),
			@ApiImplicitParam(name = "label", required = true),
			@ApiImplicitParam(name = "value", required = true),
			@ApiImplicitParam(name = "type", required = true),
			@ApiImplicitParam(name = "description", required = true),
			@ApiImplicitParam(name = "status", required = true),
			@ApiImplicitParam(name = "remarks", required = true),
	})
	@PostMapping(value = "/add")
	@ResponseBody
	@MethodLog(module = "字典数据新增", insertDB = true)
	public ResultBean add(@RequestBody SysDictDataVo sysDictDataVo) {
		if (null == sysDictDataVo.getParentId()) {
			sysDictDataVo.setParentId(0L);
		}
		List<String> messageList = ValidateFilter.getFilterMessage(sysDictDataVo, Constants.VALIDATE_DEFAULT);
		if (!messageList.isEmpty()) {
			return ResultBean.error(messageList.toString());
		}
		if (isRepeat(sysDictDataVo))
			return ResultBean.error("字典键值" + MessageCodes.get(MessageCodes.M980014));

		SysDictData sysDictData = new SysDictData();
		BeanUtils.copyProperties(sysDictDataVo, sysDictData);
		SysDictData.putTimeAndUser(sysDictData);
		sysDictData.setDeleted(0);
		sysDictDataService.save(sysDictData);
		return ResultBean.ok(sysDictData);
	}

	/**
	 * <p><b>Title:</b> isRepeat</p>
	 * <p><b>Description:</b> 判断字典数据表名称是否重复</p>
	 *
	 * @param sysDictDataVo
	 * @author douzi
	 */
	private boolean isRepeat(SysDictDataVo sysDictDataVo) {
		SysDictData temp = new SysDictData();
		if (sysDictDataVo.getValue() == null || sysDictDataVo.getType() == null) {
			return false;
		}
		temp.setType(sysDictDataVo.getType());
		temp.setValue(sysDictDataVo.getValue());
		temp.setDeleted(0);
		Optional<SysDictData> sysDictDataOpt = sysDictDataService.findOne(Example.of(temp));
		if (sysDictDataOpt.isPresent()) {
			SysDictData sysDictData = sysDictDataOpt.get();
			if (sysDictDataVo.getId() != null && !sysDictDataVo.getId().equals(sysDictData.getId()))
				return true;
			else return sysDictDataVo.getId() == null;
		}
		return false;
	}

	@ApiOperation("字典数据详情")
	@ApiImplicitParam(name = "id", required = true, paramType = "query", dataType = "Long")
	@GetMapping(value = "/get")
	@ResponseBody
	public ResultBean get(Long id) {
		SysDictData sysDictData = sysDictDataService.get(id);
		return ResultBean.ok(substrParentIds(sysDictData));
	}

	@ApiOperation("字典数据变更")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "id", required = true),
			@ApiImplicitParam(name = "parentId", required = true),
			@ApiImplicitParam(name = "parentIds", required = true),
			@ApiImplicitParam(name = "sort", required = true),
			@ApiImplicitParam(name = "isleaf", required = true),
			@ApiImplicitParam(name = "label", required = true),
			@ApiImplicitParam(name = "value", required = true),
			@ApiImplicitParam(name = "type", required = true),
			@ApiImplicitParam(name = "description", required = true),
			@ApiImplicitParam(name = "status", required = true),
			@ApiImplicitParam(name = "remarks", required = true),
	})
	@PutMapping(value = "/edit")
	@ResponseBody
	@MethodLog(module = "字典数据变更", insertDB = true, opterate = 2)
	public ResultBean update(@RequestBody SysDictDataVo sysDictDataVo) {
		if (null == sysDictDataVo.getParentId()) {
			sysDictDataVo.setParentId(0L);
		}
		List<String> messageList = ValidateFilter.getFilterMessage(sysDictDataVo, Constants.VALIDATE_UPDATE);
		if (!messageList.isEmpty()) {
			return ResultBean.error(messageList.toString());
		}
		//字典不能修改type，为了防止修改，自己先赋值type
		SysDictData bcDict1 = sysDictDataService.get(sysDictDataVo.getId());
		sysDictDataVo.setType(bcDict1.getType());
		if (isRepeat(sysDictDataVo))
			return ResultBean.error("字典键值" + MessageCodes.get(MessageCodes.M980014));

		SysDictData sysDictData = new SysDictData();
		BeanUtils.copyProperties(sysDictDataVo, sysDictData);
		sysDictData.setDeleted(0);
		return ResultBean.ok(sysDictDataService.merge(sysDictData));
	}

	@ApiOperation("字典数据删除")
	@ApiImplicitParam(name = "id", required = true, paramType = "query", dataType = "Long")
	@DeleteMapping(value = "/del")
	@ResponseBody
	@MethodLog(module = "字典数据删除", insertDB = true, opterate = 3)
	public ResultBean delete(Long id) {
		if (id == null) {
			return ResultBean.error("数据id传值不能为空！");
		}

		SysDictData dictData = sysDictDataService.findById(id);
		if(dictData.getDeleted()==0){
			return ResultBean.error("该数据为启用状态，不能删除！");
		}
		dictData.setDeleted(1);
		String msg = sysDictDataService.deleteLogic(dictData);
		if(!msg.isEmpty()){
			return ResultBean.error(msg);
		}
		return ResultBean.ok();
	}

	@ApiOperation("字典数据状态修改")
	@ApiImplicitParam(name = "id", required = true, paramType = "query", dataType = "Long")
	@GetMapping(value = "/update-status")
	@ResponseBody
	@MethodLog(module = "字典数据状态修改", insertDB = true, opterate = 2)
	public ResultBean updateStatus(Long id, Integer status) {
		if (id == null || status == null) {
			return ResultBean.error("数据id或类型传值不能为空！");
		}
		if (!(status == 0 || status == 2)) {
			return ResultBean.error("状态值传值错误！");
		}
		SysDictData dictData = sysDictDataService.findById(id);
		dictData.setDeleted(status);
		String msg = sysDictDataService.deleteLogic(dictData);
		if(!msg.isEmpty()){
			return ResultBean.error(msg);
		}
		return ResultBean.ok();
	}

	@MethodLog(module = "字典批量排序", insertDB = true, opterate = 2)
	@ApiOperation("字典批量排序")
	@ApiImplicitParam(name = "list", required = true, paramType = "query", dataType = "Long")
	@PutMapping(value = "/sorts")
	@ResponseBody
	public ResultBean updateDictSort(@RequestBody List<SysDictDataVo> list) {
		for (SysDictDataVo bcDictVo : list) {
			ResultBean result = update(bcDictVo);
			if (!result.getCode().equals("0")) {
				return ResultBean.error(result.getMsg());
			}
		}
		return ResultBean.ok();
	}

	/***
	 * @Description
	 * @Date 15:59 2019/8/31
	 * @Param [type, flag]
	 * @return com.wondertek.oes.commons.utils.ResultBean
	 **/
	@MethodLog(module = "根据type查询全部数据")
	@ApiOperation("根据type查询全部数据")
	@ApiImplicitParam(name = "type", required = true, paramType = "query", dataType = "String")
	@GetMapping("/all")
	public ResultBean getAll() {
		/*if (null == tfVo.getTypes() || tfVo.getTypes().length == 0) {
			if (StringUtils.isBlank(tfVo.getFlag())) {
				return ResultBean.error("types或flag至少有一个参数不能为空");
			}
		}*/
		Map<String, List<SysDictData>> map = new LinkedHashMap<>();
		//flag为1的时候查全量数据，详情页面调的接口
		List<SysDictType> all = sysDictTypeService.findAll();
		for (SysDictType dictType : all) {
			List<SysDictData> allByType = sysDictDataService.findAllByType(dictType.getType());
			map.put(dictType.getType(), allByType);
		}
		return ResultBean.ok(map);

	}


	@MethodLog(module = "根据type查询全部数据")
	@ApiOperation("根据type查询全部数据")
	@ApiImplicitParam(name = "type", required = true, paramType = "query", dataType = "String")
	@GetMapping("/get-by-type")
	public ResultBean findAllByTypeGet(String type) {
		return ResultBean.ok(sysDictDataService.findAllByType(type));
	}

	@ApiOperation("字典缓存刷新")
	@GetMapping(value = "/cache-refresh")
	@ResponseBody
	@MethodLog(module = "字典缓存刷新", insertDB = true, opterate = 2)
	public ResultBean findByLikeType() {
		Set<String> keys = redisTemplate.keys(Constants.REDIS_KEY_BCDICT_TYPE + "*");
		redisTemplate.delete(keys);
		SysDictType dictType = new SysDictType();
		dictType.setDeleted(0);
		List<SysDictType> all = sysDictTypeService.findAll(Example.of(dictType));
		for (SysDictType sysDictType : all) {
			sysDictDataService.findAllByType(sysDictType.getType());
		}
		return ResultBean.ok();
	}

	@MethodLog(module = "字典下拉框树查询")
	@ApiOperation("字典下拉框树查询")
	@ApiImplicitParam(name = "type", required = true, paramType = "query", dataType = "String")
	@GetMapping("/tree-data")
	public ResultBean findBcDictTree(String type, Long excludeId) {
		SysDictData sysDictData = new SysDictData();
		if (StringUtils.isBlank(type)) {
			throw new BusinessException(MessageCodes.M980717);
		}

		sysDictData.setType(type);
		List<SysDictData> allList = sysDictDataService.findAll(Example.of(sysDictData));
		List<SysDictData> resultList = new ArrayList<>();
		// 过滤被排除的编码（包括所有子级）
		for (SysDictData data : allList) {
			if (null != excludeId) {
				if (data.getId().equals(excludeId)) {
					continue;
				}
				if (data.getParentIds().contains("," + excludeId)) {
					continue;
				}
			}
			resultList.add(data);
		}
		List<SysDictData> list = new ArrayList<>();
		setDictTree(0L, resultList, list);
		return ResultBean.ok(list);
	}

	private void setDictTree(Long parentId, List<SysDictData> all, List<SysDictData> list, Map<Long, SysDictData> allMap) {
		all.forEach(sysDictData -> {
			if (parentId.equals(sysDictData.getParentId())) {
				list.add(substrParentIds(sysDictData));
				allMap.remove(sysDictData.getId());
				List<SysDictData> child = new ArrayList<>();
				sysDictData.setChildren(child);
				setDictTree(sysDictData.getId(), all, child, allMap);
			}
		});
	}

	/***
	  * @Author wzq
	  * @Description //把所有数据all形成树放在list中
	  * @Date 14:02 2019/12/10
	  * @Param [parentId, all, list]
	  * @return void
	**/
	private void setDictTree(Long parentId, List<SysDictData> all, List<SysDictData> list) {
		all.forEach(sysDictData -> {
			if (parentId.equals(sysDictData.getParentId())) {
				list.add(substrParentIds(sysDictData));
				List<SysDictData> child = new ArrayList<>();
				sysDictData.setChildren(child);
				setDictTree(sysDictData.getId(), all, child);
			}
		});
	}

	private SysDictData substrParentIds(SysDictData sysDictData) {
		//前端绑定了parentids做显示,我本身的parentids是0,1,2 前端需要1,2才能绑定，所以这里截取了一下
		if (sysDictData.getParentIds().length() > 1) {
			sysDictData.setParentIds(sysDictData.getParentIds().substring(2));
		}
		return sysDictData;
	}
}
